package com.smart.config.core;

import com.google.gson.reflect.TypeToken;
import com.smart.config.ConfigProperties;
import com.smart.config.NotifyThreadLocal;
import com.smart.config.utils.GsonTool;
import com.smart.config.annotation.DynamicValue;
import com.smart.config.constant.RedisConstant;
import com.smart.config.model.ConfigVal;
import com.smart.config.model.ListenerModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.List;
import java.util.function.Consumer;

/**
 * @Author xiaoqiang
 * @Version DynamicValueProcessor.java, v 0.1 2025年03月17日 21:39 xiaoqiang
 * @Description: TODO
 */
public class DynamicValueProcessor implements BeanPostProcessor {


    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicValueProcessor.class);

    private ConfigProperties properties;

    private ConfigManager configManager;

    public DynamicValueProcessor(ConfigManager configManager,
                                 ConfigProperties properties) {
        this.configManager = configManager;
        this.properties = properties;
    }

    @Override
    public synchronized Object postProcessAfterInitialization(Object bean, String beanName) {
        ReflectionUtils.doWithFields(bean.getClass(), field -> {
            DynamicValue annotation = field.getAnnotation(DynamicValue.class);
            if (annotation == null) {
                return;
            }

            String realKey
                    = RedisConstant.buildRedisKey(properties.getAppName(), annotation.group(), annotation.dataId());

            setValToField(bean, field, realKey);

            List<ListenerModel> modelList = configManager.getListeners(realKey);
            ListenerModel model = new ListenerModel(field, bean, realKey);
            if (CollectionUtils.isEmpty(modelList)) {
                configManager.registerListener(realKey, model);
                return;
            }
            checkFieldType(field, modelList);
            configManager.registerListener(realKey, model);

        });
        return bean;
    }

    private static void checkFieldType(Field field, List<ListenerModel> modelList) {
        for (ListenerModel modelTmp : modelList) {
            Field preField = modelTmp.getField();
            if (preField.getType() != (field.getType())) {
                throw new RuntimeException("listener field type not match" + preField.getType() + "!=" + field.getType());
            }
        }
    }



    private void setValToField(Object bean, Field field, String realKey) {
        try{
            Object redisConfigValue = configManager.getValue(realKey);
            if (redisConfigValue == null) {
                return;
            }
            Type type = TypeToken.get(field.getGenericType()).getType();
            Object objectVal = GsonTool.fromJson(GsonTool.toJsonString(redisConfigValue), type);

            field.setAccessible(true);
            field.set(bean, objectVal);
        }catch (Exception e){
            LOGGER.warn("[DynamicValueProcessor#setValToField]setValToField error, realKey:{}, redisValue:{}, field:{}, bean:{}",
                    realKey, field.getName(), bean.getClass().getName(), e);
           throw new RuntimeException(e);
        }
    }
}